package stdio.costa.imoca.api;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import stdio.costa.imoca.dto.AddressListDTO;
import stdio.costa.imoca.model.Address;
import stdio.costa.imoca.model.Image;
import stdio.costa.imoca.model.Postcard;
import stdio.costa.imoca.model.PostcardTemplate;
import stdio.costa.imoca.task.PostcardMaker;

import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataParam;

@Path("/postcard")
@Component
@Scope("request")
public class PostcardApi {

	private static final Logger logger = LoggerFactory.getLogger(PostcardApi.class);
	
	@Autowired
	private ImageApi imageApi;
	
	@PersistenceContext
	private EntityManager entityManager;

	@Autowired
	private PostcardMaker postcardMaker;
	
	@POST
	@Consumes(MediaType.MULTIPART_FORM_DATA)
	@Produces({ "application/json;qs=1", "application/xml;qs=.5" })
	@Transactional
	public List<Postcard> create(@FormDataParam("photo") FormDataBodyPart photoPart, @FormDataParam("wish") FormDataBodyPart wishPart,
			@FormDataParam("addresses") String addressString, @FormDataParam("templateUuid") String templateUuid, @FormDataParam("postmarkUuids") String postmarkUuidString) throws Exception {
		ObjectMapper mapper = new ObjectMapper();
		AddressListDTO wrapper = mapper.readValue(addressString, AddressListDTO.class);
		List<Postcard> postcards = new ArrayList<Postcard>(wrapper.getAddresses().size());
		logger.info("Creating postcards with {} addresses targeted.", wrapper.getAddresses().size());
		Image photo = imageApi.create(photoPart);
		Image wish = imageApi.create(wishPart);
		List<Image> postmarks = getPostmarks(postmarkUuidString);
		PostcardTemplate template = entityManager.find(PostcardTemplate.class, templateUuid);
		for(Address address : wrapper.getAddresses()) {
			Postcard postcard = createPostcard(photo, wish, address, postmarks, template);
			postcards.add(postcard);
		}
		
		return postcards;
	}
	
	@GET
	@Path("/{uuid}")
	@Produces({ "application/json;qs=1", "application/xml;qs=.5" })
	public Postcard get(@PathParam("uuid") String uuid) {
		return entityManager.find(Postcard.class, uuid);
	}

	@SuppressWarnings("unchecked")
	protected List<Image> getPostmarks(String postmarkUuidString) {
		if(StringUtils.isNotBlank(postmarkUuidString)) {
			String[] postmarkUuids = postmarkUuidString.split(",");
			return entityManager.createNamedQuery("listByUuids").setParameter("uuids", Arrays.asList(postmarkUuids)).getResultList();
			
		}
		return null;
	}
	
	@Path("/photo")
	@POST
	@Consumes(MediaType.MULTIPART_FORM_DATA)
	@Produces({ "application/json;qs=1", "application/xml;qs=.5" })
	@Transactional
	public Postcard addPhoto(@FormDataParam("postcardUuid") String postcardUuid, @FormDataParam("photo") FormDataBodyPart photoPart) throws IOException {
		Image photo = imageApi.create(photoPart);
		Postcard postcard = null;
		if(StringUtils.isBlank(postcardUuid)) {
			postcard = new Postcard();
			postcard.setPhoto(photo);
			entityManager.persist(postcard);
		} else {
			postcard = entityManager.find(Postcard.class, postcardUuid);
			postcard.setPhoto(photo);
			entityManager.merge(postcard);
		}
		
		return postcard;
	}
	
	@Path("/wish")
	@POST
	@Consumes(MediaType.MULTIPART_FORM_DATA)
	@Produces({ "application/json;qs=1", "application/xml;qs=.5" })
	@Transactional
	public Postcard addWish(@FormDataParam("postcardUuid") String postcardUuid, @FormDataParam("wish") FormDataBodyPart wishPart) throws IOException {
		Image photo = imageApi.create(wishPart);
		Postcard postcard = null;
		if(StringUtils.isBlank(postcardUuid)) {
			postcard = new Postcard();
			postcard.setWish(photo);
			entityManager.persist(postcard);
		} else {
			postcard = entityManager.find(Postcard.class, postcardUuid);
			postcard.setWish(photo);
			entityManager.merge(postcard);
		}
		
		return postcard;
	}

	@Path("/postmark")
	@POST
	@Produces({ "application/json;qs=1", "application/xml;qs=.5" })
	@Transactional
	public Postcard addPostmark(@FormParam("postcardUuid") String postcardUuid, @FormParam("postmarkUuid") String postmarkImageUuid) throws IOException {
		Image postmark = entityManager.find(Image.class, postmarkImageUuid);
		Postcard postcard = null;
		if(StringUtils.isBlank(postcardUuid)) {
			postcard = new Postcard();
			postcard.addPostmarks(postmark);
			entityManager.persist(postcard);
		} else {
			postcard = entityManager.find(Postcard.class, postcardUuid);
			postcard.addPostmarks(postmark);
			entityManager.merge(postcard);
		}
		return postcard;
	}
	
	@Path("/template")
	@POST
	@Produces({ "application/json;qs=1", "application/xml;qs=.5" })
	@Transactional
	public Postcard addTemplate(@FormParam("postcardUuid") String postcardUuid, @FormParam("templateUuid") String templateUuid) {
		PostcardTemplate template = entityManager.find(PostcardTemplate.class, templateUuid);
		Postcard postcard = null;
		if(StringUtils.isBlank(postcardUuid)) {
			postcard = new Postcard();
			postcard.setTemplate(template);
			entityManager.persist(postcard);
		} else {
			postcard = entityManager.find(Postcard.class, postcardUuid);
			postcard.setTemplate(template);
			entityManager.merge(postcard);
		}
		return postcard;
	}

	private Postcard createPostcard(Image photo, Image wish, Address address, List<Image> postmarks, PostcardTemplate template) throws Exception {
		Postcard postcard = new Postcard(photo, wish, address, postmarks, template);
		entityManager.persist(postcard);
		if(postcard.isReadyToMake()) {
			postcardMaker.make(postcard);
		} else {
			// TODO notify
		}
		return postcard;
	}
}
